using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using UniversalAdminSystem.Infrastructure.Configs;

namespace UniversalAdminSystem.Infrastructure.Services;

public partial class K2ModelService
{
    private readonly K2Config _k2Config;
    private readonly ILogger<K2ModelService> _logger;
    private readonly HttpClient _httpClient;
    public event OnContentChunkReceivedHandler? OnContentChunkReceived;

    public delegate void OnContentChunkReceivedHandler(string chunk);

    public K2ModelService(IOptions<K2Config> k2Config, ILogger<K2ModelService> logger, IHttpClientFactory httpClientFactory)
    {
        _k2Config = k2Config.Value;
        _logger = logger;
        _httpClient = httpClientFactory.CreateClient("K2Client");
        _httpClient.BaseAddress = new Uri(_k2Config.BaseUrl);
        _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_k2Config.ApiKey}");
        _httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
    }

    public async IAsyncEnumerable<string> SendChatRequestAsync(List<K2Message> messages, string model = "Moonshot-Kimi-K2-Instruct", float temperature = 0.7f, int maxTokens = 1000)
    {
        HttpRequestMessage request;
        HttpResponseMessage response;
        try
        {
            _logger.LogInformation("开始发送K2模型请求，使用模型: {Model}", model);
            var k2Request = new K2Request
            {
                Model = model,
                Messages = messages,
                Temperature = temperature,
                MaxTokens = maxTokens
            };
            request = new HttpRequestMessage(HttpMethod.Post, $"{_k2Config.BaseUrl}chat/completions")
            {
                Content = new StringContent(JsonSerializer.Serialize(k2Request, new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                }), Encoding.UTF8, "application/json")
            };
            response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, CancellationToken.None);
            response.EnsureSuccessStatusCode();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "K2模型请求过程中发生错误");
            throw;
        }
        await using var responseStream = await response.Content.ReadAsStreamAsync();
        var sb = new StringBuilder();
        await foreach (var chunk in ParseStreamingResponseAsync(responseStream, sb))
        {
            yield return chunk;
        }
        _logger.LogInformation("K2模型请求成功完成");
    }

    private async IAsyncEnumerable<string> ParseStreamingResponseAsync(Stream responseStream, StringBuilder answer)
    {
        using var reader = new StreamReader(responseStream);
        var responseId = "";
        var responseModel = "";
        long responseCreated = 0;
        var responseObject = "";

        var chunk = new K2StreamResponse();
        while (!reader.EndOfStream)
        {
            var line = await reader.ReadLineAsync();
            if (string.IsNullOrWhiteSpace(line)) continue;
            var trimmedLine = line.Trim();
            if (trimmedLine.StartsWith("data: "))
            {
                var jsonData = trimmedLine.Substring(6);
                if (jsonData.Trim() == "[DONE]") continue;
                try
                {
                    // 解析每个数据块
                    chunk = JsonSerializer.Deserialize<K2StreamResponse>(jsonData, new JsonSerializerOptions
                    {
                        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                    });
                }
                catch (JsonException ex)
                {
                    _logger.LogWarning("解析数据块失败: {JsonData}, 错误: {Error}", jsonData, ex.Message);
                }

                if (chunk != null)
                {
                    // 保存响应元数据
                    if (!string.IsNullOrEmpty(chunk.Id)) responseId = chunk.Id;
                    if (!string.IsNullOrEmpty(chunk.Model)) responseModel = chunk.Model;
                    if (!string.IsNullOrEmpty(chunk.Object)) responseObject = chunk.Object;
                    if (chunk.Created > 0) responseCreated = chunk.Created;

                    // 处理choices
                    if (chunk.Choices != null && chunk.Choices.Count > 0)
                    {
                        var choice = chunk.Choices[0];
                        if (choice.Delta != null && !string.IsNullOrEmpty(choice.Delta.Content))
                        {
                            answer.Append(choice.Delta.Content);
                            OnContentChunkReceived?.Invoke(choice.Delta.Content);
                            yield return choice.Delta.Content;
                        }
                    }
                }
            }
        }
    }

    public async Task<List<string>> SendChunkingRequestAsync(string preprocessedJson)
    {
        HttpRequestMessage request;
        HttpResponseMessage response;
        try
        {
            string model = "Moonshot-Kimi-K2-Instruct"; float temperature = 0.7f; int maxTokens = 1000;
            _logger.LogInformation("开始发送K2模型请求，使用模型: {Model}", model);
            var k2Request = new K2Request
            {
                Model = model,
                Messages = {
                    new K2Message { Role = "system", Content = "你是一个文本分片专家，任务是将文本分割成合适大小的块（chunk），每个 chunk 不超过 500 个 token。在分片时需要遵守以下规则：1. 尽量在句子边界进行切分。2. 不要将命名实体（例如人名、地名、作品名等）拆分到不同 chunk 中。3. 尽可能保证每个 chunk 的语义完整。4. 如果文本中有无标点长句，可以在合适位置手动加切分点，但要保证语义不被破坏。" },
                    new K2Message { Role = "user", Content = $"帮我完成精准的分片，以下是文本的预处理结果：\n{preprocessedJson}。\n必须以Json格式返回结果，每个分片包含chunk_id、content、token_count字段" },
                },
                Temperature = temperature,
                MaxTokens = maxTokens,
            };
            request = new HttpRequestMessage(HttpMethod.Post, $"{_k2Config.BaseUrl}chat/completions")
            {
                Content = new StringContent(JsonSerializer.Serialize(k2Request, new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                }), Encoding.UTF8, "application/json")
            };
            response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, CancellationToken.None);
            response.EnsureSuccessStatusCode();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "K2模型请求过程中发生错误");
            throw;
        }
        await using var responseStream = await response.Content.ReadAsStreamAsync();
        var sb = new StringBuilder();
        await foreach (var chunk in ParseStreamingResponseAsync(responseStream, sb)) { }

        return ParseChunk(sb.ToString());
    }

    public List<string> ParseChunk(string chunkJson)
    {
        var chunks = new List<string>();
        using var jsonDoc = JsonDocument.Parse(chunkJson);

        JsonElement root = jsonDoc.RootElement;

        // 如果根是对象并且包含 "chunks"
        if (root.ValueKind == JsonValueKind.Object && root.TryGetProperty("chunks", out var chunksProp))
        {
            if (chunksProp.ValueKind == JsonValueKind.Array)
            {
                foreach (var chunk in chunksProp.EnumerateArray())
                    ExtractContent(chunk, chunks);
            }
        }
        else if (root.ValueKind == JsonValueKind.Array)
        {
            foreach (var chunk in root.EnumerateArray())
                ExtractContent(chunk, chunks);
        }

        return chunks;
    }

    private void ExtractContent(JsonElement chunk, List<string> chunks)
    {
        if (chunk.TryGetProperty("content", out var jsonContent))
        {
            var content = jsonContent.GetString();
            if (!string.IsNullOrEmpty(content))
                chunks.Add(content);
        }
    }
}